package com.vst.orm.search.hibernate;

import java.io.Serializable;
import org.hibernate.EntityMode;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;

import com.vst.orm.search.Metadata;

public class HibernateEntityMetadata implements Metadata {
	private SessionFactory sessionFactory;
	private ClassMetadata metadata;
	private Class<?> collectionType;

	public HibernateEntityMetadata(SessionFactory sessionFactory, ClassMetadata classMetaData,
			Class<?> collectionType) {
		this.sessionFactory = sessionFactory;
		this.metadata = classMetaData;
		this.collectionType = collectionType;
	}

	public String getIdProperty() {
		return this.metadata.getIdentifierPropertyName();
	}

	public Metadata getIdType() {
		return new HibernateNonEntityMetadata(this.sessionFactory, this.metadata.getIdentifierType(), null);
	}

	public Serializable getIdValue(Object object) {
		if ((object instanceof HibernateProxy)) {
			return ((HibernateProxy) object).getHibernateLazyInitializer().getIdentifier();
		}
		return this.metadata.getIdentifier(object);
	}

	public Class<?> getJavaClass() {
		return this.metadata.getMappedClass();
	}

	public String[] getProperties() {
		String[] pn = this.metadata.getPropertyNames();
		String[] result = new String[pn.length + 1];
		result[0] = this.metadata.getIdentifierPropertyName();
		for (int i = 0; i < pn.length; i++) {
			result[(i + 1)] = pn[i];
		}
		return result;
	}

	public Metadata getPropertyType(String property) {
		Type pType = this.metadata.getPropertyType(property);
		Class<?> pCollectionType = null;
		if (pType.isCollectionType()) {
			pType = ((CollectionType) pType).getElementType((SessionFactoryImplementor) this.sessionFactory);
			pCollectionType = pType.getReturnedClass();
		}
		if (pType.isEntityType()) {
			return new HibernateEntityMetadata(this.sessionFactory,
					this.sessionFactory.getClassMetadata(((EntityType) pType).getName()), pCollectionType);
		}
		return new HibernateNonEntityMetadata(this.sessionFactory, pType, pCollectionType);
	}

	public Object getPropertyValue(Object object, String property) {
		if (getIdProperty().equals(property)) {
			return this.metadata.getIdentifier(object);
		}
		return this.metadata.getPropertyValue(object, property);
	}

	public boolean isCollection() {
		return this.collectionType != null;
	}

	public Class<?> getCollectionClass() {
		return this.collectionType;
	}

	public boolean isEmeddable() {
		return false;
	}

	public boolean isEntity() {
		return true;
	}

	public boolean isNumeric() {
		return false;
	}

	public boolean isString() {
		return false;
	}
}
